package com.gitee.qdbp.jdbc.support;

import java.net.URL;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.gitee.qdbp.able.exception.ResourceNotFoundException;
import com.gitee.qdbp.tools.crypto.GlobalCipherTools;
import com.gitee.qdbp.tools.files.PathTools;
import com.gitee.qdbp.tools.utils.PropertyTools;

class AutoDataSourceTools {

    // jdbc:oracle:thin:@//192.168.1.218:1521/DbName
    // jdbc:oracle:thin:192.168.1.218:1521:DbSid
    // jdbc:oracle:thin:@TnsName
    // jdbc:db2://192.168.1.218:60000/DbName
    // jdbc:db2://192.168.1.218:60000/DbName:currentSchema=SchemaName;
    // jdbc:h2:~/DbName // 嵌入式
    // jdbc:h2:mem:DbName // 内存数据库
    // jdbc:h2:tcp://192.168.1.218:8084/~/DbName
    // jdbc:sqlserver://192.168.1.218:1433;DatabaseName=DbName
    // jdbc:sqlite::memory:
    // jdbc:sqlite://F:/sqlite/main.db
    // jdbc:sqlite://home/sqlite/main.db
    // jdbc:sqlite::resource:settings/sqlite/main.db

    // dbname可以是一个文件路径
    // 如 jdbc.xxx=sqlite.file@~/E:/sqlite/main.db
    // 如 jdbc.xxx=sqlite.file@~/home/sqlite/main.db
    /** 解析数据库配置的正则表达式 **/
    private static final Pattern CONFIG = Pattern.compile(
        //    dbtype.subtype     : username      : password  @address/           dbname            :   schema   ?EncryptedPassword
        "(\\w+?(?:\\.\\w+)?)(?::([\\-.\\w]+))?(?::(.+?))?@([^@/?]+)/((?:[a-zA-Z]:/)?[/\\-.\\w]+)(?::(.+?))?(?:\\?(.+))?");

    public static void parseConfigString(String configString, DataSourceConfig config) {
        if (configString.equals(config.getConfigString())) {
            return; // 未变化, 无需重新解析
        }

        // 解析配置参数
        Matcher matcher = CONFIG.matcher(configString.trim());
        if (!matcher.matches()) {
            String one = "dbtype:username:password@address/dbname";
            String two = "dbtype:username@address/dbname?EncryptedPassword";
            String msg = "Config string format error -->  " + configString + "\nformat <1> " + one + " <2> " + two;
            throw new IllegalArgumentException(msg);
        }
        config.setConfigString(configString);

        // dbtype:username:password@address/dbname:schema?EncryptedPassword
        int i = 1;
        String dbtype = matcher.group(i++);
        String username = matcher.group(i++);
        String password = matcher.group(i++);
        String dbaddress = matcher.group(i++);
        String dbname = matcher.group(i++);
        String dbschema = matcher.group(i++);
        String encrypted = matcher.group(i);
        if (password != null && encrypted != null) {
            String desc = "password and EncryptedPassword coexistence is not allowed.";
            throw new IllegalArgumentException("Config string format error. " + desc);
        }

        config.setDbType(dbtype);
        config.setDbAddress(dbaddress);
        config.setDbName(dbname);
        config.setDbSchema(dbschema);
        config.setUserName(username);
        if (encrypted != null) {
            config.setPassword(GlobalCipherTools.decrypt("db", encrypted.getBytes()));
        } else if (password != null) {
            config.setPassword(password.getBytes());
        }
    }

    public static Properties loadDefaultProperties() {
        // 查找默认配置文件
        // 1. {classpath}/settings/qdbc/jdbc.auto.properties<br>
        // 2. qdbc-jdbc-core.jar!/settings/qdbc/jdbc.auto.properties<br>
        try { // 新版本移了位置, 从qdbc-jdbc-spring.jar移到qdbc-jdbc-core.jar
            URL path = PathTools.findResource("settings/qdbc/jdbc.auto.properties", AutoDruidDataSource.class);
            return PropertyTools.load(path);
        } catch (ResourceNotFoundException e) { // 兼容旧版本
            URL path = PathTools.findResource("settings/jdbc/jdbc.auto.properties", AutoDruidDataSource.class);
            return PropertyTools.load(path);
        }
    }

    /** 推断特殊的Driver(druid.1.1.22以上版本不需要了,已贡献到主版本) **/
    // https://github.com/alibaba/druid/pull/3698
    public static String resolveSpecialDriver(String jdbcUrl) {
        if (jdbcUrl == null) {
            return null;
        }
        if (jdbcUrl.startsWith("jdbc:db2")) {
            return resolveDb2Driver(jdbcUrl);
        }
        return null;
    }

    private static String resolveDb2Driver(String jdbcUrl) {
        // 优化DB2 Driver的推断逻辑, 参考自 https://www.cnblogs.com/lidg/articles/3588566.html
        // Resolve the DB2 driver from JDBC URL
        // Type2 COM.ibm.db2.jdbc.app.DB2Driver, url = jdbc:db2:databasename
        // Type3 COM.ibm.db2.jdbc.net.DB2Driver, url = jdbc:db2:ServerIP:6789:databasename
        // Type4 8.1+ com.ibm.db2.jcc.DB2Driver, url = jdbc:db2://ServerIP:50000/databasename
        String prefix = "jdbc:db2:";
        if (jdbcUrl.startsWith(prefix + "//")) { // Type4
            return "com.ibm.db2.jcc.DB2Driver";
        } else {
            String suffix = jdbcUrl.substring(prefix.length());
            if (suffix.indexOf(':') > 0) { // Type3
                return "COM.ibm.db2.jdbc.net.DB2Driver";
            } else { // Type2
                return "COM.ibm.db2.jdbc.app.DB2Driver";
            }
        }
    }
}
